package com.itfreer.power;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.itfreer.power.entity.logging.LogInfo;
import com.itfreer.power.entity.user.VUserInfoEntity;
import com.itfreer.power.service.logging.LoggingService;
import com.itfreer.power.service.power.PowerService;
import com.itfreer.utils.filter.FilterInterception;
import com.itfreer.utils.filter.FilterResult;
import com.itfreer.utils.filter.UrlMatchUtils;
import com.itfreer.utils.sys.SystemParameter;

/**
 * 用户访问权限过滤器
 */
public class UserPowerFilterInterception implements FilterInterception {

	protected final Logger logger = LoggerFactory.getLogger(getClass());
	
	private final static String mkLogin = "power/mklogin";

	private final static String user_attributes = "user_attributes";
	private final static String user_id = "user_id";
	private final static String s_user = "s_user";
	private final static String CanAccessUrl = "CanAccessUrl";
	private final static String CanAccessData = "CanAccessData";

	@Autowired(required = false)
	private LoggingService loggingService;
	@Autowired
	private SystemParameter systemParameter;
	@Autowired
	private PowerService powerService;

	private int index;

	@Override
	public Integer getIndex() {
		return index;
	}

	@Override
	public void setIndex(Integer index) {
		this.index = index;
	}

	@SuppressWarnings("unchecked")
	@Override
	public FilterResult doFilter(HttpServletRequest request, HttpServletResponse response, String servletPath) {
		// 准备日志
		LogInfo info = new LogInfo();
		info.setId(UUID.randomUUID().toString().replaceAll("-", ""));
		info.setFunName(servletPath);
		info.setFunType("功能访问");
		info.setTime(new Date());
		info.setIp("");

		final HttpSession httpSession = request.getSession(false);
		VUserInfoEntity userEntity = httpSession != null ? (VUserInfoEntity) httpSession.getAttribute(s_user) : null;
		if (userEntity != null) {
			info.setUser(userEntity.getUserid());
		} else {
			info.setUser("匿名用户");
		}

		// 2.再确保用户登录
		List<String> canAccessUrl = null;
		if (userEntity == null) {
			// 获取登录用户id
			final Map<String, Object> userAttribute = httpSession != null
					? (Map<String, Object>) httpSession.getAttribute(user_attributes) : null;
			if (userAttribute == null) {
				info.setInfo("未登录系统！");
				info.setResult("失败");
				logging(info);

				logger.debug("访问【" + servletPath + "】权限不够，未登录系统。");
				try {
					response.sendError(400, "访问权限不够！");
				} catch (IOException e) {
					e.printStackTrace();
				}
				return new FilterResult(true, true);
			}

			String userId = null;
			if (userAttribute.containsKey(user_id)) {
				userId = userAttribute.get(user_id).toString();
			}
			if (userId == null) {
				String ouserid = user_id.toUpperCase();
				if (userAttribute.containsKey(ouserid)) {
					userId = userAttribute.get(ouserid).toString();
				}
			}

			String userName = null;
			if (userAttribute.containsKey("name")) {
				userName = userAttribute.get("name").toString();
			}

			if (userId == null && userName == null) {
				info.setInfo("无法获取用户信息！");
				info.setResult("失败");
				logging(info);

				logger.debug("访问【" + servletPath + "】权限不够，无法获取用户信息。");
				try {
					response.sendError(400, "访问权限不够！");
				} catch (IOException e) {
					e.printStackTrace();
				}
				return new FilterResult(true, true);
			}

			// 获取用户信息
			userEntity = powerService.getUser(userId, userName);
			if (userEntity == null) {
				info.setInfo("无法获取用户！");
				info.setResult("失败");
				logging(info);

				logger.debug("访问【" + servletPath + "】权限不够，无法获取用户。");
				try {
					response.sendError(400, "访问权限不够！");
				} catch (IOException e) {
					e.printStackTrace();
				}
				return new FilterResult(true, true);
			}
			
			httpSession.setAttribute(s_user, userEntity);
			httpSession.setAttribute(user_id, userEntity.getUserid());
			// 设置用户权限
			if (userEntity.getRoleList() == null) {
				userEntity.setRoleList(powerService.getUserRoles(userEntity.getUserid()));
			}
			// 设置可访问的url地址
			canAccessUrl = powerService.getRoleUrls(userEntity.getRoleList(), systemParameter.getsId());
			httpSession.setAttribute(CanAccessUrl, canAccessUrl);
			// 设置可访问的数据权限
			Map<String, List<String>> canAccessData = powerService.getRoleDatas(userEntity.getRoleList(), systemParameter.getsId());
			httpSession.setAttribute(CanAccessData, canAccessData);
		} else {
			canAccessUrl = httpSession != null ? (List<String>) httpSession.getAttribute(CanAccessUrl) : null;
		}

		// 3.最后确认用户权限过滤
		return urlResourceDecide(servletPath, userEntity, request, response, info, canAccessUrl);
	}

	/**
	 * 决策资源
	 * 
	 * @param rqUrl
	 * @param authentication
	 * @throws ServletException
	 * @throws IOException
	 */
	private FilterResult urlResourceDecide(String rqUrl, VUserInfoEntity userEntity, HttpServletRequest request,
			HttpServletResponse response, LogInfo info, List<String> canAccessUrl) {
		
		// 是登录请求
		if(isMkLoginRequest(request)) {
			try {
				OutputStream stream = response.getOutputStream();
				String result = "{\"isOk\": true}";
				stream.write(result.getBytes("UTF-8"));
			} catch (IOException e) {
				e.printStackTrace();
			}
			return new FilterResult(true, true);
		}
		
		if (userEntity.getIsSuperAdmin() != null && userEntity.getIsSuperAdmin()) {
			info.setInfo("超级管理员");
			info.setResult("成功");
			logging(info);
			return new FilterResult(false, true);
		} else {
			if (canAccessUrl == null) {
				info.setInfo("可访问地址为空！");
				info.setResult("失败");
				logging(info);

				logger.debug("访问【" + rqUrl + "】权限不够，可访问地址为空。");
				try {
					response.sendError(400, "访问权限不够！");
				} catch (IOException e) {
					e.printStackTrace();
				}
				return new FilterResult(true, true);
			} else {
				if (exclude(canAccessUrl, rqUrl)) {
					info.setInfo(null);
					info.setResult("成功");
					logging(info);
					return new FilterResult(false, true);
				} else {
					info.setInfo("没有可访问权限！");
					info.setResult("失败");
					logging(info);
					logger.debug("访问【" + rqUrl + "】权限不够，没有可访问权限。");
					try {
						response.sendError(400, "访问权限不够！");
					} catch (IOException e) {
						e.printStackTrace();
					}
					return new FilterResult(true, true);
				}
			}
		}
	}

	/**
	 * 是否是模拟请求
	 * 
	 * @param request
	 * @return
	 */
	private boolean isMkLoginRequest(final HttpServletRequest request) {
		return request.getRequestURI().endsWith(mkLogin) || request.getRequestURI().endsWith(mkLogin+"/");
	}
	
	/**
	 * 是否匹配
	 * 
	 * @param url
	 * @return
	 */
	private boolean exclude(List<String> excludeUrls, String url) {
		// 过滤模式，过滤掉无需保护资源
		for (String pattern : excludeUrls) {
			if (UrlMatchUtils.match(pattern, url)) {
				return true;
			}
		}
		return false;
	}

	private void logging(LogInfo info) {
		if (loggingService == null) {
			logger.debug("loggingService为null");
			return;
		}
		LoggingThread loggingThread = new LoggingThread(info);
		loggingThread.start();
	}

	private class LoggingThread extends Thread {
		private LogInfo info;

		public LoggingThread(LogInfo info) {
			this.info = info;
		}

		public void run() {
			loggingService.logging(info);
		}
	}
}